﻿/*
 * Copyright (c) 2015-2016 Constantijn Evenhuis (blueprints@const.nl)
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
using Blueprints.IO;
using Blueprints.Validation;
using System.Collections.Generic;

namespace Blueprints.Editing
{
    partial class EditContext
    {
        private readonly Dictionary<int, IValidatedNode> validatedNodes = new Dictionary<int, IValidatedNode>();
        private readonly Dictionary<int, EditNode> editNodes = new Dictionary<int, EditNode>();

        internal int Version
        {
            get;
            private set;
        }

        internal bool TryGetValidatedNode(EditNode editNode, out IValidatedNode node)
        {
            return validatedNodes.TryGetValue(editNode.TraceableNode.TraceId, out node);
        }

        internal EditNode GetEditNode(IValidatedNode validatedNode)
        {
            if (validatedNode == null)
            {
                return null;
            }

            ITraceableNode traceableNode = validatedNode.Node as ITraceableNode;
            if (traceableNode == null)
            {
                return null;
            }

            EditNode editNode;
            if (!editNodes.TryGetValue(traceableNode.TraceId, out editNode))
            {
                return null;
            }

            return editNode;
        }

        private int Synchronize(EditNode selected)
        {
            editNodes.Clear();
            validatedNodes.Clear();
            Version++;

            List<ITraceableNode> traceableNodes = new List<ITraceableNode>();
            foreach (EditNode node in Nodes)
            {
                ITraceableNode traceableNode = node.TraceableNode;
                editNodes[traceableNode.TraceId] = node;
                traceableNodes.Add(traceableNode);
            }

            string rootType = Nodes[0].Type ?? typeof(object).AssemblyQualifiedName;
            IValidatedNode root = ValidationProvider.Validate(new NodeReader(DocumentUri, traceableNodes), rootType);
            foreach (IValidatedNode node in Walk(root))
            {
                validatedNodes[((ITraceableNode)node.Node).TraceId] = node;
            }

            OnBlueprintChanged(selected);
            return Version;
        }

        private IEnumerable<IValidatedNode> Walk(IValidatedNode root)
        {
            yield return root;
            foreach (IValidatedNode element in root.Elements)
            {
                foreach (IValidatedNode descendant in Walk(element))
                {
                    yield return descendant;
                }
            }

            foreach (IValidatedProperty property in root.Properties.Values)
            {
                if (property.Node == null)
                {
                    continue;
                }

                foreach (IValidatedNode descendant in Walk(property.Node))
                {
                    yield return descendant;
                }
            }
        }
    }
}